﻿using anydata.Entitys;
using MongoDB.Driver;
using Newtonsoft.Json.Linq;
using System;
using System.Diagnostics;

namespace anydata.Extensions
{

    public static class DataProviderExtensions
    {
        public static async Task<OperateResult> UpdateById(this DataProvider provider, TokenModel token, string collName, string id, UpdateDefinition<EntityBase> update)
        {
            var coll = provider.TryGetCollection<EntityBase>(token, collName);
            if (coll.success)
            {
                var filter = Builders<EntityBase>.Filter.Eq(i => i.id, id);
                update.CurrentDate(i => i.updateTime);
                await coll.data.UpdateOneAsync(filter, update);
                return OperateResult.Success(new { });
            }
            return OperateResult.Faild($"{collName} 更新操作失败！");
        }

    }
    public static class FieldsProviderExtensions
    {
        public const string PropertyCollName = "standard-property";

        public static async Task<List<FormField>> GetChangeFields(this DataProvider provider, TokenModel token)
        {
            var obj = provider.TryGetCollection<XProperty>(token, PropertyCollName);
            if (obj.success)
            {
                var properties = await obj.data.Find(item => item.isChangeSource == true || item.isChangeTarget == true).ToListAsync();
                return properties.Select(item => item.ToField()).ToList();
            }
            return new();
        }
    }

    public static class FinancialProviderExtensions
    {
        public const string FinancialInfoObject = "target-financial";
        public const string DepreciationConfigObject = "depreciation-config";
        public const string FinancialPeriodCollName = "financial-period";

        public static async Task<FinancialInfo> GetFinancialInfo(this DataProvider provider, TokenModel token)
        {
            var obj = await provider.GetObjectAsync(token, FinancialInfoObject);
            if (obj is null)
            {
                return new FinancialInfo();
            }
            return obj.ToObject<FinancialInfo>() ?? new FinancialInfo();
        }

        public static async Task<XDepreciationConfig?> GetDepreciationConfig(this DataProvider provider, TokenModel token)
        {
            var obj = await provider.GetObjectAsync(token, DepreciationConfigObject);
            if (obj is null)
            {
                return null;
            }
            return obj.ToObject<XDepreciationConfig>();
        }

        public static async Task<XPeriod?> GetFinancialPeriod(this DataProvider provider, TokenModel token, string id)
        {
            var obj = provider.TryGetCollection<XPeriod>(token, FinancialPeriodCollName);
            if (obj.success)
            {
                return await obj.data.Find(item => item.id == id).FirstOrDefaultAsync();
            }
            return null;
        }

        public static async Task<OperateResult> UpdateOperationId(this DataProvider provider, TokenModel token, string id, string? operationId)
        {
            var update = Builders<EntityBase>.Update.Set("operationId", operationId);
            return await provider.UpdateById(token, FinancialPeriodCollName, id, update);
        }

        public static async Task<OperateResult> UpdateDepreciationStatus(this DataProvider provider, TokenModel token, string id, bool depreciated)
        {
            var update = Builders<EntityBase>.Update.Set("depreciated", depreciated);
            return await provider.UpdateById(token, FinancialPeriodCollName, id, update);
        }
    }

    public static class OperationProviderExtensions
    {
        public const string OperationLogCollName = "operation-log";

        public static async Task<XOperationLog?> GetOperationLog(this DataProvider provider, TokenModel token, string id)
        {
            var obj = provider.TryGetCollection<XOperationLog>(token, OperationLogCollName);
            if (obj.success)
            {
                return await obj.data.Find(item => item.id == id).FirstOrDefaultAsync();
            }
            return null;
        }

        public static async Task<OperateResult> UpdateOperationProgress(this DataProvider provider, TokenModel token, string id, int complete, int total)
        {
            var progress = total == 0 ? 0 : complete * 100.0 / total;
            var update = Builders<EntityBase>.Update.Set("progress", Math.Round(progress, 2));
            return await provider.UpdateById(token, OperationLogCollName, id, update);
        }

        public static async Task<OperateResult> UpdateOperationStatus(this DataProvider provider, TokenModel token, string id, int status)
        {
            var update = Builders<EntityBase>.Update.Set("status", status);
            return await provider.UpdateById(token, OperationLogCollName, id, update);
        }

        public static async Task<OperateResult> UpdateOperationRemark(this DataProvider provider, TokenModel token, string id, string remark)
        {
            var update = Builders<EntityBase>.Update.Set("remark", remark);
            return await provider.UpdateById(token, OperationLogCollName, id, update);
        }

        public static async Task<OperateResult> InsertOperation(this DataProvider provider, TokenModel token, XOperationLog opertion)
        {
            return await provider.InsertAsync(token, OperationLogCollName, JArray.FromObject(new List<XOperationLog>() { opertion }));
        }
    }
    public static class FormProviderExtensions
    {
        public const string FormCollName = "standard-view";
        public const string SpeciesItemCollName = "standard-species-item";

        public static async Task<XForm?> findForm(this DataProvider provider, TokenModel token, string id)
        {
            var formColl = provider.TryGetCollection<XForm>(token, FormCollName);
            if (formColl.success)
            {
                var form = await formColl.data.Find(item => item.id == id).FirstOrDefaultAsync();
                return await WithFormFields(provider, token, form);
            }
            return null;
        }

        public static async Task<XForm> WithFormFields(this DataProvider provider, TokenModel token, XForm form)
        {
            var itemColl = provider.TryGetCollection<XSpeciesItem>(token, SpeciesItemCollName);
            if (itemColl.success)
            {
                List<string> tags = new() { "选择型", "分类型" };
                var properties = form.attributes.Where(item => item.property is not null).Select(item => item.property).ToList();
                var speciesIds = properties.Where(prop => tags.Contains(prop.valueType) && prop.speciesId is not null).Select(item => item.speciesId).Distinct();
                var items = await itemColl.data.Find(item => speciesIds.Contains(item.speciesId)).ToListAsync();
                var group = items.GroupBy(item => item.speciesId ?? "unknown").ToDictionary(g => g.Key, g => g.ToList());
                form.fields = form.attributes.Where(item => item.property is not null).Select(attr =>
                {
                    var field = attr.ToField();
                    if (attr.property.speciesId is not null)
                    {
                        if (group.ContainsKey(attr.speciesId))
                        {
                            var items = group[attr.speciesId];
                            field.lookups = items.Select(item =>
                            {
                                return new LookupModel
                                {
                                    id = item.id,
                                    code = item.info,
                                    text = item.name,
                                    value = "S" + item.id,
                                    parentId = item.parentId,
                                };
                            }).ToList();
                        }
                    }
                    return field;
                }).ToList();
            }
            return form;
        }
    }
}
